﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Xml.Linq;
using System.Xml;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using Huirui.Cavan.Core.Settings;
using Huirui.Cavan.Core.Helper;
using Huirui.Cavan.Domain.MainBoundedContext.AttachmentModule;
using Huirui.Cavan.Core.Extension;

namespace Huirui.Cavan.Application.MainBoundedContext.AttachmentModule
{
    public class FileUploadAppService : IFileUploadAppService
    {
        public IAttachmentAppService AttachmentAppService { get; set; }

        #region 上传文件
        /// <summary>
        /// Uploads the file.
        /// </summary>
        /// <param name="request">The request.</param>
        public void UploadFile(FileUploadRequest request)
        {
            int iAttachmentGroupID = request.AttachmentGroupID;
            string strDirectory = Global.Settings.ImageTempSavePath + request.FileDirectory;
            string strFileName = request.FileName;
            Stream sourceStream = request.FileData;

            if (!sourceStream.CanRead)
            {
                return;
            }
            CreateDirectory(strDirectory);

            SaveFile(strDirectory + strFileName, request);

            if (JudgeNeedCompress(iAttachmentGroupID))
            {
                List<Size> lsize = GetCompressFormate(iAttachmentGroupID);
                using (FileStream fileStream = new FileStream(strDirectory + strFileName, FileMode.Open))
                {
                    foreach (Size s in lsize)
                    {
                        fileStream.Position = 0;
                        string strCompressionFilePath = CreateFilePath(strDirectory + strFileName, s, GetFileSuffix(strFileName));

                        ImageResize(fileStream, s, strCompressionFilePath, request.WaterMark);
                    }
                }
            }
        }
        #endregion

        #region 删除文件
        public void DeleteFile(FileDeleteRequest request)
        {
            int iAttachmentGroupID = request.AttachmentGroupID;
            string strDirectory = Global.Settings.ImageSavePath + request.FileDirectory;
            string strFileName = request.FileName;
            string strFilePath = strDirectory + strFileName;
            if (File.Exists(strFilePath))
            {
                File.Delete(strFilePath);
            }
            if (JudgeNeedCompress(iAttachmentGroupID))
            {
                List<Size> lsize = GetCompressFormate(iAttachmentGroupID);
                foreach (Size s in lsize)
                {
                    strFilePath = strDirectory + strFileName + "_" + s.Width.ToString() + "@" + s.Height.ToString() + GetSaveFileSuffix(iAttachmentGroupID);
                    if (File.Exists(strFilePath))
                    {
                        File.Delete(strFilePath);
                    }
                }
            }

        }
        #endregion

        #region 拷贝文件
        /// <summary>
        /// Copies the file.
        /// </summary>
        /// <param name="strFilePath">The STR file path.</param>
        public void CopyFile(string strDirectory, string strFileName, string prefix)
        {
            if (strDirectory != "" && strFileName != "")
            {
                string originalFileName = prefix.IsNotEmpty() ? strFileName.Replace(prefix, "") : strFileName;
                if (originalFileName.Contains("_"))
                {
                    strFileName = originalFileName.Split('_')[0];
                }
                string strRawDirectory = Global.Settings.ImageTempSavePath + strDirectory.Replace("/", "\\");
                string strNewDirectory = Global.Settings.ImageSavePath + strDirectory.Replace("/", "\\");

                CreateDirectory(strNewDirectory);

                DirectoryInfo di = new DirectoryInfo(strRawDirectory);
                FileInfo[] fi = di.GetFiles();
                foreach (FileInfo f in fi)
                {
                    if (f.Name.Contains(strFileName))
                    {
                        f.CopyTo(strNewDirectory + prefix + f.Name, true);
                    }
                }
                foreach (FileInfo f in fi)
                {
                    if (f.Name.Contains(strFileName))
                    {
                        f.Delete();
                    }
                }
            }
        }
        #endregion

        #region 创建文件夹
        /// <summary>
        /// Creates the directory.
        /// </summary>
        /// <param name="strDirectory">The STR directory.</param>
        public void CreateDirectory(string strDirectory)
        {
            if (!Directory.Exists(strDirectory))
            {
                Directory.CreateDirectory(strDirectory);
            }
        }
        #endregion

        #region 压缩文件
        public void ImageResize(Stream stream, Size size, string strFilePath, bool mark)
        {
            if (mark && size.Height >= 120 && size.Width >= 120)
            {
                string waterFilePath = strFilePath + "_water.jpg";
                WaterMark(stream, size, waterFilePath);

                using (MagickNet.Image img = new MagickNet.Image(waterFilePath))
                {
                    MagickNet.Geometry geo = new MagickNet.Geometry(size.Width, size.Height, 0, 0);
                    img.Resize(geo);
                    img.Write(strFilePath);
                }

                File.Delete(waterFilePath);
            }
            else
            {
                using (MagickNet.Image img = new MagickNet.Image(stream))
                {
                    MagickNet.Geometry geo = new MagickNet.Geometry(size.Width, size.Height, 0, 0);
                    img.Resize(geo);
                    img.Write(strFilePath);
                }
            }
        }
        public void WaterMark(Stream stream, Size size, string strFilePath)
        {
            using (Image img = Image.FromStream(stream))
            {
                size = size.Width == 0 || size.Height == 0 ? img.Size : size;
                size = CutPhotoHelper.NewSize(size.Width, size.Height, img.Width, img.Height);
                using (Image bitmap = new Bitmap(size.Width, size.Height))
                {
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        using (Image markImg = Image.FromFile(Global.Settings.WaterMarkPath))
                        {
                            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            g.SmoothingMode = SmoothingMode.HighQuality;
                            g.Clear(System.Drawing.Color.Transparent);

                            g.DrawImage(img, new System.Drawing.Rectangle(0, 0, size.Width, size.Height),
                                new Rectangle(0, 0, img.Size.Width, img.Size.Height),
                                GraphicsUnit.Pixel);

                            Size waterSize = GetWaterSize(markImg.Width, markImg.Height);
                            Point waterPoint = GetWaterPoint(size, waterSize);

                            g.DrawImage(markImg, waterPoint.X, waterPoint.Y, waterSize.Width, waterSize.Height);

                            bitmap.Save(strFilePath, ImageFormat.Bmp);
                        }
                    }
                }
            }
        }

        private Point GetWaterPoint(Size imgSize, Size waterSize)
        {
            Identifier.WaterMarkVeSite veSite = (Identifier.WaterMarkVeSite)Global.Settings.WaterMarkVeSite;
            Identifier.WaterMarkHoSite hoSite = (Identifier.WaterMarkHoSite)Global.Settings.WaterMarkHoSite;
            int marginX = Global.Settings.WaterMarkMarginX;
            int marginY = Global.Settings.WaterMarkMarginY;
            int waterW = Global.Settings.WaterMarkWidth;
            int waterH = Global.Settings.WaterMarkHeight;

            waterW = waterW > 0 ? waterW : waterSize.Width;
            waterH = waterH > 0 ? waterH : waterSize.Height;

            Point point = new Point();
            if (veSite == Identifier.WaterMarkVeSite.Top)
                point.Y = marginY;
            else if (veSite == Identifier.WaterMarkVeSite.Center)
                point.Y = Convert.ToInt32((imgSize.Height - waterH) / 2);
            else
                point.Y = imgSize.Height - waterH - marginY;

            if (hoSite == Identifier.WaterMarkHoSite.Left)
                point.X = marginX;
            else if (hoSite == Identifier.WaterMarkHoSite.Middle)
                point.X = Convert.ToInt32((imgSize.Width - waterW) / 2);
            else
                point.X = imgSize.Width - waterW - marginX;

            return point;
        }
        private Size GetWaterSize(int waterW, int waterH)
        {
            int w = Global.Settings.WaterMarkWidth;
            int h = Global.Settings.WaterMarkHeight;

            Size size = new Size();
            size.Width = w > 0 ? w : waterW;
            size.Height = h > 0 ? h : waterH;
            return size;
        }
        #endregion

        #region 图片填充
        /*
        /// <summary>
        /// Fills the background.
        /// </summary>
        /// <param name="strFilePath">The STR file path.</param>
        /// <param name="formateSize">Size of the formate.</param>
        public void FillBackground(string strFilePath, int iAttachmentGroupID, Size formateSize)
        {
            StringBuilder backGroundFilePathBuilder = new StringBuilder();
            backGroundFilePathBuilder.Append(ConfigurationManager.AppSettings["ResourcePath"]);
            backGroundFilePathBuilder.Append("\\");
            backGroundFilePathBuilder.Append(iAttachmentGroupID.ToString());
            backGroundFilePathBuilder.Append("\\");
            backGroundFilePathBuilder.Append(formateSize.Width.ToString());
            backGroundFilePathBuilder.Append("@");
            backGroundFilePathBuilder.Append(formateSize.Height.ToString());
            backGroundFilePathBuilder.Append(".gif");

            MagickNet.Image imgBackground = new MagickNet.Image(backGroundFilePathBuilder.ToString());
            MagickNet.Image imgResource = new MagickNet.Image(strFilePath);

            imgBackground.Composite(imgResource, MagickNet.GravityType.CenterGravity);
            imgBackground.Write(strFilePath);

            imgBackground.Dispose();
            imgResource.Dispose();
        }*/
        #endregion

        #region 保存文件
        /// <summary>
        /// Saves the file.
        /// </summary>
        /// <param name="strFilePath">The STR file path.</param>
        /// <param name="memoryStream">The memory stream.</param>
        public void SaveFile(string strFilePath, MemoryStream memoryStream)
        {
            FileStream dumpFile = new FileStream(strFilePath, FileMode.Create, FileAccess.ReadWrite);
            memoryStream.WriteTo(dumpFile);
            memoryStream.Dispose();
            dumpFile.Dispose();
        }
        #endregion

        #region 保存原文件
        /// <summary>
        /// Saves the file.
        /// </summary>
        /// <param name="strFilePath">The STR file path.</param>
        /// <param name="request">The request.</param>
        public void SaveFile(string strFilePath, FileUploadRequest request)
        {
            Stream sourceStream = request.FileData;

            using (FileStream targetStream = new FileStream(strFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                const int iBufferLen = 4096;
                byte[] buffer = new byte[iBufferLen];
                int iCount = 0;
                while ((iCount = sourceStream.Read(buffer, 0, iBufferLen)) > 0)
                {
                    targetStream.Write(buffer, 0, iCount);
                }
                targetStream.Dispose();
                sourceStream.Dispose();
            }
        }
        #endregion

        #region 判断是否需要压缩
        /// <summary>
        /// Judges the need compress.
        /// </summary>
        /// <param name="iAttachmentGroupID">The i Attachment group ID.</param>
        /// <returns></returns>
        public bool JudgeNeedCompress(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            if (attachmentGroup != null)
            {
                return attachmentGroup.IsNeedCompress;
            }
            return false;
        }
        #endregion

        #region 获取文件路径
        /// <summary>
        /// Gets the directory.
        /// </summary>
        /// <param name="iAttachmentGroupID">The i Attachment group ID.</param>
        /// <returns></returns>
        public string GetDirectory(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            StringBuilder sbDirectory = new StringBuilder("");
            if (attachmentGroup != null)
            {
                sbDirectory.Append("\\");
                sbDirectory.Append(attachmentGroup.EnglishName);
                sbDirectory.Append("\\");
                sbDirectory.Append(DateTime.Now.Year.ToString());
                sbDirectory.Append("\\");
                sbDirectory.Append(DateTime.Now.Month.ToString());
                sbDirectory.Append("\\");
                sbDirectory.Append(DateTime.Now.Day.ToString());
                sbDirectory.Append("\\");
                sbDirectory.Append("i" + attachmentGroup.FileServer.ToString());
                sbDirectory.Append("\\");
            }
            return sbDirectory.ToString();
        }
        #endregion

        #region 获取限定文件大小
        public long GetRestrictFileLength(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            long lRestrictFileLength = 0;
            if (attachmentGroup != null)
            {
                lRestrictFileLength = long.Parse(attachmentGroup.RestrictFileLength.ToString());
            }
            return lRestrictFileLength;
        }
        #endregion

        #region 获取文件后缀
        /// <summary>
        /// Gets the file suffix.
        /// </summary>
        /// <param name="strFileName">Name of the STR file.</param>
        /// <returns></returns>
        public string GetFileSuffix(string strFileName)
        {
            string strFileSuffix = "";
            if (strFileName.IndexOf(".") > -1)
                strFileSuffix = strFileName.Substring(strFileName.LastIndexOf("."));
            return strFileSuffix;
        }
        #endregion

        #region 获取限定文件后缀
        public string GetRestrictFileSuffix(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            if (attachmentGroup != null)
            {
                return attachmentGroup.FileSuffixs;
            }
            return "";
        }
        #endregion

        #region 获取保存后文件后缀
        public string GetSaveFileSuffix(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            if (attachmentGroup != null)
            {
                return attachmentGroup.SaveFileSuffix;
            }
            return "";
        }
        #endregion

        #region 创建新文件名
        /// <summary>
        /// Gets the new name of the file.
        /// </summary>
        /// <param name="iOriginalWidth">Width of the i original.</param>
        /// <param name="iOriginalHeight">Height of the i original.</param>
        /// <param name="strFileSuffix">The STR file suffix.</param>
        /// <returns></returns>
        public string GetNewFileName(int iOriginalWidth, int iOriginalHeight, string strFileSuffix)
        {
            StringBuilder sbNewFileName = new StringBuilder("");
            sbNewFileName.Append(Guid.NewGuid().ToString());
            sbNewFileName.Append("_");
            sbNewFileName.Append(iOriginalWidth.ToString());
            sbNewFileName.Append("@");
            sbNewFileName.Append(iOriginalHeight.ToString());
            sbNewFileName.Append(strFileSuffix);

            return sbNewFileName.ToString();
        }
        #endregion

        #region 创建文件路径
        /// <summary>
        /// Creates the file path.
        /// </summary>
        /// <param name="strFilePath">The STR file path.</param>
        /// <param name="size">The size.</param>
        /// <param name="strFileSuffix">The STR file suffix.</param>
        /// <returns></returns>
        public string CreateFilePath(string strFilePath, Size size, string strFileSuffix)
        {
            StringBuilder sbFilePath = new StringBuilder(strFilePath);
            sbFilePath.Append("_");
            if (size.Width != 0 && size.Height != 0)
            {
                sbFilePath.Append(size.Width.ToString());
                sbFilePath.Append("@");
                sbFilePath.Append(size.Height.ToString());
            }
            sbFilePath.Append(strFileSuffix);

            return sbFilePath.ToString();
        }
        #endregion

        #region 获取限定格式
        /// <summary>
        /// Gets the restrict formate.
        /// </summary>
        /// <param name="iAttachmentGroupID">The i attachment group ID.</param>
        /// <returns></returns>
        public string GetRestrictFormate(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            if (attachmentGroup != null)
            {
                return attachmentGroup.RestrictFormate;
            }
            return "";
        }
        #endregion

        #region 获取压缩格式
        /// <summary>
        /// Gets the compress formate.
        /// </summary>
        /// <param name="iAttachmentGroupID">The i Attachment group ID.</param>
        /// <returns></returns>
        public List<Size> GetCompressFormate(int attachmentGroupID)
        {
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            List<Size> lsize = new List<Size>();
            if (attachmentGroup != null)
            {
                string[] strCompressFormates = attachmentGroup.CompressFormate.Split('|');
                string[] widthAndHeight;
                foreach (string strCompressFormate in strCompressFormates)
                {
                    if (strCompressFormate.Contains("@"))
                    {
                        widthAndHeight = strCompressFormate.Split('@');
                        lsize.Add(new Size(int.Parse(widthAndHeight[0]), int.Parse(widthAndHeight[1])));
                    }

                }
            }
            return lsize;
        }
        #endregion

        #region 获取文件新大小
        /// <summary>
        /// Gets the new size.
        /// </summary>
        /// <param name="newWidth">The new width.</param>
        /// <param name="newHeight">The new height.</param>
        /// <param name="orginalWidth">Width of the orginal.</param>
        /// <param name="orginalHeight">Height of the orginal.</param>
        /// <returns></returns>
        public Size GetNewSize(int newWidth, int newHeight, int orginalWidth, int orginalHeight)
        {
            int finalWidth = 0;
            int finalHeight = 0;

            if (orginalWidth < newWidth && orginalHeight < newHeight) //保留原图
            {
                finalWidth = orginalWidth;
                finalHeight = orginalHeight;
            }
            else if (orginalWidth / orginalHeight > newWidth / newHeight) //按高缩放
            {
                finalWidth = newWidth;
                finalHeight = (finalWidth * orginalHeight) / orginalWidth;
            }
            else //按宽缩放
            {
                finalHeight = newHeight;
                finalWidth = (finalHeight * orginalWidth) / orginalHeight;
            }

            return new Size(finalWidth, finalHeight);
        }
        #endregion

        #region 获取文件限定数量
        public int GetRestrictFileCount(int attachmentGroupID)
        {
            int restrictFileCount = 0;
            AttachmentGroup attachmentGroup = AttachmentAppService.GetAttachmentGroupByID(attachmentGroupID);
            if (attachmentGroup != null)
            {
                restrictFileCount = attachmentGroup.RestrictFileCount;
            }
            return restrictFileCount;
        }
        #endregion

        #region 截取图片
        public void CutPhoto(int attachmentGroupID, string directory, string oldFileName, string newFileName, int partWidth, int partHeight, int origStartPointX, int origStartPointY)
        {
            string oldFile = Global.Settings.ImageTempSavePath + directory.Replace("/", "\\") + oldFileName;
            string newFile = Global.Settings.ImageTempSavePath + directory.Replace("/", "\\") + newFileName;
            if (File.Exists(oldFile))
                using (Image image = Image.FromFile(oldFile))
                {
                    using (Bitmap cutMap = CutPhotoHelper.CutPic(image, partWidth, partHeight, origStartPointX, origStartPointY, image.Width, image.Height))
                    {
                        cutMap.Save(newFile, ImageFormat.Bmp);

                        if (JudgeNeedCompress(attachmentGroupID))
                        {
                            using (FileStream fileStream = new FileStream(newFile, FileMode.Open))
                            {
                                using (Image img = Image.FromStream(fileStream))
                                {
                                    List<Size> lsize = GetCompressFormate(attachmentGroupID);
                                    foreach (Size s in lsize)
                                    {
                                        fileStream.Position = 0;
                                        string compressFilePath = CreateFilePath(newFile, s, GetFileSuffix(newFile));
                                        ImageResize(fileStream, s, compressFilePath, false);
                                    }
                                }
                            }
                        }
                    }
                }
        }
        #endregion

        #region 删除文件
        public void DeleteFile(string directory, string fileName)
        {
            directory = Global.Settings.ImageSavePath + directory.Replace("/", "\\");

            DirectoryInfo di = new DirectoryInfo(directory);
            if (di.Exists)
            {
                FileInfo[] fi = di.GetFiles();
                foreach (FileInfo f in fi)
                {
                    if (f.Name.Contains(fileName))
                    {
                        f.Delete();
                    }
                }
            }
        }
        #endregion
    }
}
